package com.forte.fortePoiUtils.commons;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 数据与工具类,提供了两种文件的扩展名,字母序号表,以及一些需要用到的辅助方法
 * @author ForteScarlet
 * <div>
 *		<ul>
 *  		<li> ---><a href='https://gitee.com/ForteScarlet' target='_block'>码云个人地址</a></li> </li>
 *		</ul>
 * </div>
 */
public class Datas {
	

	//静态代码块加载字母顺序
	static{

		Map<String , Integer> wordNum = new HashMap<>();

		for(int i = 1;i<= 26;i++){
			char c = (char)(97 + (i-1));
			wordNum.put(c + "" , i);
		}

		//获取字母顺序表
		Map<String , Integer> map = wordNum;
		
		//保存
		WORD_NUMBER = map;
		
	}
	
	/** 2003版excel的后缀 */
	public static final String HSSF_END = "xls";
	
	/** 2010+的excel的后缀 */
	public static final String XSSF_END = "xlsx";
	
	/** 字母顺序表 */
	public static final Map<String , Integer> WORD_NUMBER;
	
	/** 创建随机文件名时，日期的格式 */
	public static final String DATE_FORMAT = "yyyy-MM-dd-HHmmss";
	
	/**
	 * 获取Excel中列的数字坐标<br>
	 * 例如:"AA" => 27
	 * @param colStr
	 * 		Excel中的列坐标
	 * @return
	 * 		此列坐标对应的数字
	 * @author ForteScarlet
	 */
	public static long getStringNum(String colStr){
		//获取数组
		char[] array = colStr.toCharArray();
		//长度
		int length = array.length;
		//初始数
		long end = 1;
		
		//倒序遍历,从小位开始遍历
		for (int i = array.length - 1;i >= 0;i--) {
			//字母序号
			int num = WORD_NUMBER.get((array[i]+"").toLowerCase());
			//加成
			int addBuffer = length - i - 1;
			//结果加成
			end += num * (int)(Math.pow(26, addBuffer));
		}
		
		//返回结果
		return end ;
	}
	
	/**
	 * 获取对象的所有字段(包括没有get方法的字段) - root
	 * @param t
	 * 对象
	 * @return
	 * @author ForteScarlet
	 */
	public static List<Field> getFieldsWithoutGetter(Class<?> tClass){
		Field[] fs = tClass.getDeclaredFields();
		return Arrays.asList(fs);
	}


	/**
	 * 获取对象的所有字段(包括没有get方法的字段)
	 * @param t
	 * @param <T>
	 * @return
	 */
	public static <T> List<Field> getFieldsWithoutGetter(T t){
		return getFieldsWithoutGetter(t.getClass());
	}

	
	/**
	 * 获取对象的所有字段名(包括没有get方法的字段)
	 * @param t
	 * 对象
	 * @return
	 * @author ForteScarlet
	 */
	public static <T> List<String> getFieldsNameWithoutGetter(T t){
		return getFieldsWithoutGetter(t).stream().map(f -> f.getName()).collect(Collectors.toList());
	}
	
	/**
	 * 获取对象的所有字段 - root
	 * @param t
	 * 对象
	 * @return
	 * @author ForteScarlet
	 */
	public static List<Field> getFieldsWithGetter(Class<?> tClass){
		Field[] fs = tClass.getDeclaredFields();
		//返回时过滤掉没有get方法的字段
		return Arrays.asList(fs).stream().filter(f -> Arrays.stream(tClass.getMethods()).anyMatch(m -> m.getName().equals("get"+headUpper(f.getName())))).collect(Collectors.toList());
	}

	/**
	 * 获取对象的所有字段
	 * @param t
	 * @param <T>
	 * @return
	 */
	public static <T> List<Field> getFieldsWithGetter(T t){
		return getFieldsWithGetter(t.getClass());
	}
	
	/**
	 * 获取对象的所有字段名
	 * @param t
	 * 对象
	 * @return
	 * @author ForteScarlet
	 */
	public static <T> List<String> getFieldsNameWithGetter(T t){
		return getFieldsWithGetter(t).stream().map(f -> f.getName()).collect(Collectors.toList());
	}
	
	/**
	 * 通过对象的getter获取字段数值
	 * 支持类似“user.child”这种多层级的获取方式
	 * @param t
	 * @return
	 * @author ForteScarlet
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static <T> Object objectGetter(T t , String fieldName) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		//判断是否有用“.”分割
		String[] split = fieldName.split("\\.");
		//如果分割后只有一个字段值，直接返回
		if(split.length == 1){
			Method method = t.getClass().getMethod("get"+Datas.headUpper(fieldName));
			return method.invoke(t);
		}else{
			//否则为多层级字段,获取第一个字段名，拼接其余字段名并进行递归处理
			String field = split[0];
			//移除第一个字段
			List<String> list = Arrays.stream(split).collect(Collectors.toList());
			list.remove(0);
			//拼接剩余
			fieldName = list.stream().collect(Collectors.joining("."));

			//field必定为单层字段，获取field对应的对象，然后使用此对象进行递归
			return objectGetter(objectGetter(t , field) , fieldName);
		}
	}

	/**
	 * 通过Class对象判断是否存在此字段
	 * @param t
	 * @param field
	 * @return
	 */
	public static boolean isFieldExist(Class<?> tClass, String field) {
		//获取class对象
//		Class<? extends T> tClass = t.getClass();

		//判断是否为多层级字段
		String[] split = field.split("\\.");
		if(split.length == 1){
			//如果只有一个，直接获取
			Field getField = null;
			try {
				getField = tClass.getDeclaredField(field);
			} catch (NoSuchFieldException e) {
			}
			//如果存在，返回true，否则返回false
			if(getField == null){
				return false;
			}else{
				return true;
			}
		}else{
			//否则，存在多层级字段，先获取第一个字段并获得其类型，然后通过此类型的Class对象进一步判断
			String firstField = split[0];
			//获取字段对象
			Field getField = null;
			try {
				getField = tClass.getDeclaredField(firstField);
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			}
			//如果获取失败，直接返回false
			if(getField == null){
				return false;
			}
			Class<?> firstFieldType = getField.getType();
			//拼接剩余
			//移除第一个字段
			List<String> list = Arrays.stream(split).collect(Collectors.toList());
			list.remove(0);
			//拼接剩余
			String fieldName = list.stream().collect(Collectors.joining("."));
			return isFieldExist(tClass , fieldName);
		}
	}

	/**
	 * 通过对象实例判断字段是否存在
	 * @param t
	 * @param field
	 * @param <T>
	 * @return
	 * @throws NoSuchFieldException
	 */
	public static <T> boolean isFieldExist(T t , String field) {
		return isFieldExist(t.getClass() , field);
	}


	/**
	 * 过滤掉没有映射的字段 - 未完成
	 * @param tClass
	 * @param fieldNames
	 */
//	public static void filteField(Class<?> tClass , List<String> fieldNames , Map<String , String> result){
//		//如果映射（result）不为空，将仅保留映射中存在的字段
//		fieldNames = fieldNames.stream().filter(name -> Datas.isFieldExist(tClass , name)).collect(Collectors.toList());
//	}

	
	/**
	 * 单词开头大写
	 * @param str
	 * @return
	 * @author ForteScarlet
	 */
	public static String headUpper(String str){
		//拿到第一个字母
		String head = (str.charAt(0)+"").toUpperCase();
		//拿到其他
		String body = str.substring(1);
		return head + body;
	}
	
	/**
	 * 获取指定数量的0~9的随机数 ,返回数组格式
	 * @param number
	 * @return
	 * @author ForteScarlet
	 */
	public static Integer[] getRandomNum(int number){
		Random r = new Random();
		return Stream.iterate(1, i -> i++).limit(number).map(i -> r.nextInt(10)).toArray(Integer[]::new);
	}
	
	/**
	 * 获取指定数量的0~9的随机数 ,返回字符串格式
	 * @param number
	 * @return
	 * @author ForteScarlet
	 */
	public static String getRandomNumStr(int number){
		return Stream.of(getRandomNum(number)).map(s -> s+"").collect(Collectors.joining());
	}
	
	
	/**
	 * 获取类名
	 * @param c
	 * @return
	 * @author ForteScarlet
	 */
	public static String getClassName(Class<?> c){
		String name = c.getName();
		String[] split = name.split("\\.");
		return split[split.length - 1];
	}
	
	/**
	 * 通过对象获取类名
	 * @param o
	 * @return
	 * @author ForteScarlet
	 */
	public static String getClassName(Object o){
		return getClassName(o.getClass());
	}
	
}
